package com.seleniti.enpareja.controller.ui.view;

import java.util.ArrayList;
import java.util.Set;

import org.ioc.commons.flowcontrol.actioncontroller.ActionController;
import org.ioc.commons.flowcontrol.actioncontroller.ActionHandler;
import org.ioc.commons.flowcontrol.common.impl.ReceiverAdapter;
import org.ioc.commons.flowcontrol.eventbus.EventBus;
import org.ioc.commons.flowcontrol.logincontroller.IsLoggedUserInfoConsumer;
import org.ioc.commons.flowcontrol.messageboxfactory.MessageBoxFactory.PromptResponse;
import org.ioc.commons.flowcontrol.operationmanager.OperationManager;
import org.ioc.commons.flowcontrol.operationmanager.impl.OperationHandlerFactory;
import org.ioc.commons.model.globaldata.GlobalDataController.Consumer;
import org.ioc.commons.model.globaldata.IsGlobalDataConsumer;
import org.ioc.commons.utils.Format;
import org.ioc.commons.utils.FormatterLogger;

import com.seleniti.enpareja.controller.common.GlobalData;
import com.seleniti.enpareja.controller.common.domain.LoggedUserInfo;
import com.seleniti.enpareja.controller.model.integration.database.domain.Couple;
import com.seleniti.enpareja.controller.model.integration.database.domain.CoupleType;
import com.seleniti.enpareja.controller.model.integration.database.domain.Product;
import com.seleniti.enpareja.controller.model.integration.database.domain.Store;
import com.seleniti.enpareja.controller.ui.base.EnParejaViewBasePresenter;
import com.seleniti.enpareja.controller.ui.main.AppShell;
import com.seleniti.enpareja.controller.ui.view.PendingShoppingView.Action;
import com.seleniti.enpareja.controller.ui.view.PendingShoppingView.ActionMode;
import com.seleniti.enpareja.controller.ui.view.PendingShoppingView.Event;
import com.seleniti.enpareja.controller.ui.view.PendingShoppingView.Operation;

/**
 * Presenter for the Login view
 * 
 * @author Jesús Lunar Pérez
 * 
 */
public class PendingShoppingViewPresenter
		extends
		EnParejaViewBasePresenter<PendingShoppingView, PendingShoppingView.Event, PendingShoppingView.Operation, PendingShoppingView.Action>
		implements PendingShoppingView.Presenter, IsLoggedUserInfoConsumer<LoggedUserInfo>,
		IsGlobalDataConsumer<GlobalData> {

	private static final FormatterLogger logger = FormatterLogger.getLogger(PendingShoppingViewPresenter.class);
	private static final String UNDEFINED_STORE_NAME = "";
	private Consumer<GlobalData> consumer;

	public PendingShoppingViewPresenter(PendingShoppingView display, EventBus<Event> eventbus,
			OperationManager<Operation> operationManager, ActionController<Action> actionController) {
		super(display, eventbus, operationManager, actionController);
	}

	@Override
	public void onInitDisplay() {
		super.onInitDisplay();

		this.consumer = this.globalDataController.registerGlobalDataConsumer(this);
		display.setActionMode(ActionMode.SWITCH_LIST);

		this.loginController.requiresLoggedUserInfoIfDisplayActive(this);
		this.consumer.requires(GlobalData.UserAgent);
	}

	@Override
	protected void bindComponents() {
		super.bindComponents();
		operationManager.bindOperationsRunning(OperationHandlerFactory.<Operation> forLoaders(display));
		operationManager.bindOperationsRunning(OperationHandlerFactory.<Operation> forLoaders(shell.globalLoader()));

		shell.actionController().bindAction(AppShell.Action.DeleteNow, new ActionHandler<AppShell.Action>() {

			@Override
			public void handleAction(Object sender, com.seleniti.enpareja.controller.ui.main.AppShell.Action action,
					Object... params) {
				deleteSelected();
			}
		});
	}

	protected void deleteSelected() {
		if (display.getActionMode() == ActionMode.DELETE_ELEMENT) {
			Set<Product> selection = display.getSelection();
			Couple couple = display.couple().getValue();

			if (couple.getPendingAtStore() != null) {
				for (Store store : couple.getPendingAtStore()) {
					if (store.getProducts() != null) {
						store.getProducts().removeAll(selection);
					}
				}
				saveCouple(Operation.Saving, operationManager, true);
				display.setActionMode(ActionMode.SWITCH_LIST);
			}
		}

	}

	@Override
	public void onActive() {
		super.onActive();

		logger.info("Activating Home tasks");

		refreshData();

		shell.refreshButtonVisibility().setVisible(true);

		LoggedUserInfo lui = this.loginController.getLoggedUserInfo();

		display.setEnabled(lui != null && lui.getCoupleName() != null && !lui.getCoupleName().isEmpty());

		shell.nonAssociatedPanelVisibility().setVisible(
				lui != null && lui.isLogged() && (lui.getCoupleName() == null || lui.getCoupleName().isEmpty() || lui.getCoupleType()==CoupleType.TESTING_MODE_COUPLE));
		
		shell.firstStepsVisibility().setVisible(shell.nonAssociatedPanelVisibility().isVisible() && lui.getCoupleType()!=CoupleType.TESTING_MODE_COUPLE);
		shell.nonAssociatedButtonVisibility().setVisible(!shell.firstStepsVisibility().isVisible());

		this.consumer.ensureRequirements();
	}

	@Override
	public void onRequiredGlobalDataReady() {
		showGoBackButtonIfRequired();
	}

	@Override
	public void onRequiredGlobalDataNotReadyYet() {
		/*
		 * Nothing to do
		 */
	}

	@Override
	public void onRequiredGlobalDataUpdated(GlobalData globalDataUpdated) {
		showGoBackButtonIfRequired();
	}

	@Override
	protected void refreshData() {
		super.refreshCouple(new ReceiverAdapter<Couple>() {

			@Override
			public void success(Couple result) {
				display.storeList().clear();
				display.productsList().clear();
				display.pendingCounter().setValue(result != null ? result.getPendingProducts() : null);
				if (result != null && result.getPendingAtStore() != null) {
					display.storeList().addAll(result.getPendingAtStore());
					for (Store store : result.getPendingAtStore()) {
						for (Product element : store.getProducts()) {
							// logger.info("\ndisplay.getWhereFilter()={0}\nstore.getStoreId()={1}",
							// display.getWhereFilter() != null ?
							// display.getWhereFilter().getStoreId() : null,
							// store.getStoreId());
							if ((element.isPending() || !Boolean.TRUE.equals(display.onlyPendingFilter().getValue()))
									&& (display.getWhereFilter() == null || display.getWhereFilter().getStoreId()
											.equals(store.getStoreId()))) {
								display.productsList().add(element);
							}
						}
					}

				}
			}
		}, Operation.GettingData, operationManager, "pendingAtStore.products.where", "pendingProducts");

	}

	@Override
	public void onLoggedUserInfoDataReady() {
		refreshData();
	}

	@Override
	public void onLoggedUserInfoDataUpdated(LoggedUserInfo loggedUserInfo) {
	}

	@Override
	public void onLoggedUserInfoNotReadyYet() {
	}

	@Override
	public void onSwitchElementFromList(Product value) {
		value.setPending(!value.isPending());
		saveCouple(Operation.Saving, operationManager, true);
	}

	@Override
	public void onAddNewElement() {
		messageBoxFactory.prompt("Compra pendiente", "Escribe el nombre del artículo que quieres añadir", "",
				new PromptResponse() {

					@Override
					public void onUserResponse(boolean userResponse, String response) {
						if (userResponse && response != null && !response.isEmpty()) {
							Couple couple = display.couple().getValue();

							String text = Format.capitalize(response);
							Store store = ensureUndefinedStore(couple);
							newProductToStore(text, true, store);

							saveCouple(Operation.Saving, operationManager, true);
						}

					}
				});

	}

	private Store ensureUndefinedStore(Couple couple) {
		if (couple.getPendingAtStore() == null) {
			couple.setPendingAtStore(new ArrayList<Store>());
		}

		Store found = null;
		for (Store store : couple.getPendingAtStore()) {
			if (UNDEFINED_STORE_NAME.equals(store.getName())) {
				found = store;
				break;
			}
		}

		if (found == null) {
			found = newStore(couple);
		}

		return found;
	}

	private Store newStore(Couple couple) {
		Store found;
		found = new Store();
		found.setCouple(couple);
		found.setName(UNDEFINED_STORE_NAME);
		found.setProducts(new ArrayList<Product>());

		couple.getPendingAtStore().add(found);
		return found;
	}

	@Override
	public void onActionModeChanged() {
		ActionMode mode = display.getActionMode();

		logger.info("Action mode changed: {0}", mode);

		switch (mode) {
		case DELETE_ELEMENT:
			this.shell.deleteButtonVisibility().setVisible(true);
			break;
		default:
			this.shell.deleteButtonVisibility().setVisible(false);
		}

	}

	@Override
	public void onSelectionChanged() {
		ActionMode mode = display.getActionMode();

		logger.info("Selection changed on mode {0}", mode);

		if (mode == ActionMode.MODIFY_ELEMENT) {
			Set<Product> selection = display.getSelection();

			if (!selection.isEmpty()) {
				Product single = selection.iterator().next();

				display.modifyElement(single);
			}
		}

	}

	@Override
	public void onModifyElement(final Product element) {
		messageBoxFactory.prompt("Cambiar", "Escribe el nuevo nombre del artículo", element.getText(),
				new PromptResponse() {

					@Override
					public void onUserResponse(boolean userResponse, String response) {
						if (userResponse && response != null && !response.isEmpty()) {

							element.setText(Format.capitalize(response));

							saveCouple(Operation.Saving, operationManager, true);

							display.setActionMode(ActionMode.SWITCH_LIST);
						}

					}
				});
	}

	@Override
	public void onBoughtOrPendingButtonToggled() {
		this.refreshData();
	}

	@Override
	public void onAddAndSetNewStore(final Product element) {
		messageBoxFactory.prompt("Nuevo lugar", "Escribe el nuevo nombre del sitio donde comprarás el artículo", "",
				new PromptResponse() {

					@Override
					public void onUserResponse(boolean userResponse, String response) {
						if (userResponse && response != null && !response.isEmpty()) {
							Couple couple = display.couple().getValue();
							Store store = findStore(couple, response);

							if (store == null) {
								store = newStore(couple);
								store.setName(response);
							}

							changeStore(element, store);

							// element.getWhere().getProducts().remove(element);
							//
							// newProductToStore(element.getText(),
							// element.isPending(), stroe);
							//
							// saveAndRefreshCouple(Operation.Saving,
							// operationManager);
							//
							display.setActionMode(ActionMode.SWITCH_LIST);
						}

					}
				});

	}

	private Store findStore(Couple couple, String name) {
		Store found = null;
		for (Store store : couple.getPendingAtStore()) {
			if (store.getName().equals(name)) {
				found = store;
				break;
			}
		}
		return found;
	}

	@Override
	public void onStoreChanged(Product element, String storeId) {
		Couple couple = display.couple().getValue();

		for (Store store : couple.getPendingAtStore()) {
			if (store.getStoreId().equals(storeId)) {
				changeStore(element, store);
				return;
			}
		}

		throw new IllegalArgumentException("Store not found");
	}

	private void changeStore(Product element, Store store) {
		serviceManager.serviceFactory().pendingShoppingService().changeStore(element, store)
				.performing(Operation.Saving, operationManager).caller(this).to(new ReceiverAdapter<Void>() {

					@Override
					public void success(Void result) {
						refreshData();
					}
				});
	}

	private void newProductToStore(String text, boolean pending, Store store) {
		Product sle = new Product();
		sle.setPending(pending);
		sle.setText(text);
		sle.setWhere(store);

		store.getProducts().add(sle);
	}

	@Override
	public void onWhereFilterChanged() {
		refreshData();
		display.hideWhereFilter();
		Store filter = display.getWhereFilter();
		if (filter == null) {
			display.whereFilterText().setText("Dónde");
		} else if (filter.getName().isEmpty()) {
			display.whereFilterText().setText("Lugar sin definir");
		} else {
			display.whereFilterText().setText("En " + filter.getName());
		}
	}
}
